package com.sduept.nwld.kpi.controller;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import javax.inject.Named;
import javax.faces.view.ViewScoped;

import org.primefaces.event.NodeCollapseEvent;
import org.primefaces.event.NodeExpandEvent;
import org.primefaces.event.NodeSelectEvent;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;

import com.sduept.core.dao.SuperDAO;
import com.sduept.bigdata.web.jsf.controller.AbstractController;
import com.sduept.generator.ObjectId;
import com.sduept.nwld.dataserver.util.LibTreeNode;
import com.sduept.nwld.kpi.datasource.KpiDataSource;
import com.sduept.nwld.kpi.manager.KpiManager;
import com.sduept.nwld.kpi.model.KpiGroup;
import com.sduept.nwld.kpi.model.KpiLevel;
import com.sduept.nwld.kpi.model.KpiNormal;
import com.sduept.nwld.kpi.model.KpiWeight;

@Named
@ViewScoped
public class KpiEditController extends AbstractController{
	/**
	 * 
	 */
	private static final long serialVersionUID = 3432117710208994196L;

	@Autowired
	private KpiManager km;
	@Autowired
	private SuperDAO dao;
	
	private TreeNode root;
	private TreeNode selectedNode;
	private KpiNormal currentKpi;
	private KpiGroup currentGroup;
	private KpiDataSource currentDataSource;
	@SuppressWarnings("rawtypes")
	private Class currentType;
	
	
	private KpiNormal currentChild;
	private TreeNode selectedChildNode;
	private TreeNode croot;
	
	private List<KpiDataSource> sources;
	private List<String> selectedSourceIds = new ArrayList<String>();
	
	private List<KpiWeightComplete> dsWeights = new ArrayList<KpiWeightComplete>();
	private List<KpiWeightComplete> kpiWeights = new ArrayList<KpiWeightComplete>();
	
	private List<KpiLevel> levels = new ArrayList<KpiLevel>();
	@PostConstruct
	public void init(){
		root = new LibTreeNode("Root", null);
		List<KpiGroup> roots = km.findGroupRoots(); 
		for(KpiGroup r:roots){
			new LibTreeNode("root",r,root);
		}
		root.setExpanded(true);
		currentKpi = new KpiNormal();
		currentGroup = new KpiGroup();
		
		//按照value大小排序
		levels = km.findLevelsAllOrderByValue();
		
	}
	public void preCreateRoot(){
		currentGroup = new KpiGroup();
	}
	public void preCreateGroup(){
		currentGroup = new KpiGroup();
	}
	
	public void preCreateKpi(){
		currentKpi = new KpiNormal();
	}

	public void preCreateDataSource(){
		currentDataSource = new KpiDataSource();
	}
	
	public void createRoot(){
		if(currentGroup.getName() == ""){
			addErrorMessage("维度名称不能为空！创建失败！");
			return;
		}
		dao.create(currentGroup, KpiGroup.class);
		new LibTreeNode("root",currentGroup,root);
		addSuccessMessage("创建新维度成功！");
	}
	
	public void createGroup(){
		if(currentGroup.getName() == ""){
			addErrorMessage("维度名称不能为空！创建失败！");
			return;
		}
		if(selectedNode == null || selectedNode.getData().getClass() == KpiNormal.class){
			addErrorMessage("请选择要创建维度的父维度！创建失败！");
			return;
		}
		currentType = KpiGroup.class;
		currentGroup.setPid(((KpiGroup)selectedNode.getData()).getId());
		currentGroup.setId(ObjectId.get().toString());
		dao.create(currentGroup, KpiGroup.class);
		
		new LibTreeNode("group",currentGroup,selectedNode);
		selectedNode.getChildren().clear();
		loadChildren(selectedNode);
		selectedNode.setExpanded(true);
		addSuccessMessage("创建新维度成功！");
	}
	
	public void createKpi(){
		if(currentKpi.getName() == ""){
			addErrorMessage("指标名称不能为空！创建失败！");
			return;
		}
		if(selectedNode == null || selectedNode.getData().getClass() == KpiNormal.class){
			addErrorMessage("请选择要创建指标的父维度！创建失败！");
			return;
		}
		currentType = KpiNormal.class;
		currentKpi.setKpiGroup(((KpiGroup)selectedNode.getData()).getId());
		currentKpi.setId(ObjectId.get().toString());
		currentKpi.setKpiLevel(levels.get(0).getId());
		dao.create(currentKpi, KpiNormal.class);
		
		new LibTreeNode("normal",currentKpi,selectedNode);
		selectedNode.getChildren().clear();
		loadChildren(selectedNode);
		selectedNode.setExpanded(true);
		addSuccessMessage("创建新指标成功！");
	}
	
	public String getSelectedNodeClassName() {
		return selectedNode.getData().getClass().getSimpleName();
	}
	
	public void createDataSource(){
		if(currentDataSource.getName() == ""){
			addErrorMessage("数据源名称不能为空！创建失败！");
			return;
		}
		if(selectedNode == null ){
			addErrorMessage("请选择指标！创建失败！");
			return;
		}
		currentKpi = (KpiNormal)(selectedNode.getData());
		currentDataSource = dao.create(currentDataSource, KpiDataSource.class);
		
		//将kpi和ds的关系创建，并保存到数据库中,并添加到当前列表中
		KpiWeight w = new KpiWeight("kpinormal","kpidatasource",
				currentKpi.getId(),currentDataSource.getId());
		w = dao.createOrUpdate(w, KpiWeight.class);
		dsWeights.add(new KpiWeightComplete(w,currentKpi,currentDataSource));
		
		selectedNode.setExpanded(true);
		addSuccessMessage("创建新数据源成功！");
	}
	
	public void createCancel(){
		if(selectedNode != null){
			if(selectedNode.getData().getClass() == KpiGroup.class){
				currentGroup = (KpiGroup) selectedNode.getData();
			}else if(selectedNode.getData().getClass() == KpiNormal.class){
				currentKpi = (KpiNormal) selectedNode.getData();
			}else if(selectedNode.getData().getClass() == KpiDataSource.class){
				currentDataSource = (KpiDataSource) selectedNode.getData();
			}
		}
	}
	
	public void onNodeSelect(NodeSelectEvent event){
		selectedNode = event.getTreeNode();
		currentType = selectedNode.getData().getClass();
		if(currentType == KpiGroup.class){
			currentGroup = (KpiGroup) selectedNode.getData();
		}else if(currentType == KpiNormal.class){
			currentGroup = (KpiGroup) selectedNode.getParent().getData();
			currentKpi = (KpiNormal) selectedNode.getData();
			loadKpiWeight();
		}else if(currentType == KpiDataSource.class){
			currentGroup = (KpiGroup) selectedNode.getParent().getParent().getData();
			currentKpi = (KpiNormal) selectedNode.getParent().getData();
			currentDataSource = (KpiDataSource) selectedNode.getData();
		}
	}
	public void loadKpiWeight(){
		kpiWeights.clear();
		dsWeights.clear();
		List<KpiWeight> ws = km.findWeightsByKpi(currentKpi.getId());
		for(KpiWeight w : ws){
			if(w.getPtype().equals("kpinormal")){
				if(w.getCtype().equals("kpinormal")){
					KpiNormal p = dao.findById(w.getPid(), KpiNormal.class);
					KpiNormal c = dao.findById(w.getCid(), KpiNormal.class);
					kpiWeights.add(new KpiWeightComplete(w,p,c));
				}else if(w.getCtype().equals("kpidatasource")){
					KpiNormal p = dao.findById(w.getPid(), KpiNormal.class);
					KpiDataSource c = dao.findById(w.getCid(), KpiDataSource.class);
					dsWeights.add(new KpiWeightComplete(w,p,c));
				}
			}
		}
		currentKpi = dao.findById(currentKpi.getId(), KpiNormal.class);
	}
	public void onNodeExpand(NodeExpandEvent event){
		selectedNode = event.getTreeNode();
		currentType = selectedNode.getData().getClass();
		selectedNode.getChildren().clear();
		loadChildren(selectedNode);
		selectedNode.setExpanded(true);
	}
	@SuppressWarnings("rawtypes")
	private void loadChildren(TreeNode node){
		Class type = node.getData().getClass();
		if(type == KpiGroup.class){
			String parentId = ((KpiGroup)node.getData()).getId();
			List<KpiNormal> normals = km.findKpiByGroup(parentId);
			List<KpiGroup> groups = km.findGroupByPid(parentId);
			for(KpiGroup g : groups){
				new LibTreeNode("root",g,node);
			}
			for(KpiNormal n : normals){
				new LibTreeNode("normal",n,node);
			}
		}else if(type == KpiNormal.class){
			String parentId = ((KpiNormal)node.getData()).getId();
			List<KpiDataSource> dataSources = km.findDataSourceByKpi(parentId);
			for(KpiDataSource d : dataSources){
				new DefaultTreeNode("dataSource",d,node);
			}
		}
	}
	public void onNodeCollapse(NodeCollapseEvent event){
		event.getTreeNode().setExpanded(false);
		event.getTreeNode().getChildren().clear();
	}
	
	public void changeName(){
		if(selectedNode == null){
			addErrorMessage("请选择操作目标！");
			return;
		}
		if(currentType == KpiGroup.class){
			dao.createOrUpdate((KpiGroup)(selectedNode.getData()), KpiGroup.class);
			addSuccessMessage("重命名成功！");
		}else if(currentType == KpiNormal.class){
			dao.createOrUpdate((KpiNormal)(selectedNode.getData()), KpiNormal.class);
			loadKpiWeight();
			addSuccessMessage("重命名成功！");
		}else if(currentType == KpiDataSource.class){
			dao.createOrUpdate((KpiDataSource)(selectedNode.getData()), KpiDataSource.class);
			loadKpiWeight();
			addSuccessMessage("重命名成功！");
		}
		
	}
	
	public void save(){
		if(currentType == KpiGroup.class){
			dao.createOrUpdate(currentGroup, KpiGroup.class);
		}else if(currentType == KpiNormal.class){
			//将页面上的normal存库
			currentKpi = dao.createOrUpdate(currentKpi, KpiNormal.class);
			double count = 0d;
			//将页面上的ds和weight存库
			for(KpiWeightComplete w : dsWeights){
				w.setKpiweight(dao.createOrUpdate(w.getKpiweight(), KpiWeight.class));
				w.setChild(dao.createOrUpdate((KpiDataSource)w.getChild(), KpiDataSource.class));
				count += w.getKpiweight().getValue();
			}
			//将页面上的kpi和weight存库
			for(KpiWeightComplete w : kpiWeights){
				dao.createOrUpdate(w.getKpiweight(), KpiWeight.class);
				w.setChild(dao.createOrUpdate((KpiNormal)w.getChild(), KpiNormal.class));
				count += w.getKpiweight().getValue();
			}
			//更新指标和父指标的可靠度
			km.updateSelfAndParentsKpiReliability(currentKpi.getId());
			//取回更新完可靠度的normal
			currentKpi = dao.findById(currentKpi.getId(), KpiNormal.class);
			if(count>1){
				addErrorMessage("权重之和大于1！");
			}
			
		}else if(currentType == KpiDataSource.class){
			dao.createOrUpdate(currentDataSource, KpiDataSource.class);
			//更新父指标们的可靠度
			km.updateDsParentsKpiReliability(currentDataSource.getId());
			currentKpi = dao.findById(currentKpi.getId(), KpiNormal.class);
		}
		addSuccessMessage("保存成功");
	}
	public void delete(){
		if(selectedNode != null){
			if(currentType == KpiGroup.class){
				km.deleteGroupById(((KpiGroup)selectedNode.getData()).getId());
				addSuccessMessage("删除成功");
			}else if(currentType == KpiNormal.class){
				km.deleteKpiById(((KpiNormal)selectedNode.getData()).getId());
				addSuccessMessage("删除成功");
			}else if(currentType == KpiDataSource.class){
				String pid = ((KpiNormal)selectedNode.getParent().getData()).getId();
				String dsid = ((KpiDataSource)selectedNode.getData()).getId();
				km.removeDataSourceFromKpi(dsid, pid);
				addSuccessMessage("成功移除数据源！");
				loadKpiWeight();
			}
			selectedNode.getParent().getChildren().remove(selectedNode);
			selectedNode.clearParent();
			selectedNode = null;
			currentType = null;
		}else{
			addErrorMessage("请选择一个操作目标！");
		}
	}
	
	public void preImportDataSource(){
		sources = dao.findAll(KpiDataSource.class);
		selectedSourceIds.clear();
		//从数据源列表中删掉已经引用的数据源
		List<KpiDataSource> s =  km.findDataSourceByKpi(currentKpi.getId());
		for(int i = 0;i<s.size();i++){
			sources.remove(s.get(i));
		}
	}
	public void importDataSource(){
		if(selectedNode == null ){
			addErrorMessage("请选择指标！创建失败！");
			return;
		}
		//引入数据源。对于每一个都要建一个weight，添加到当前dsWeights中
		for(String id : selectedSourceIds){
			String pid = currentKpi.getId();
			KpiWeight w = new KpiWeight("kpinormal","kpidatasource",
					pid,id);
			w = dao.create(w, KpiWeight.class);
			dsWeights.add(new KpiWeightComplete(
					w, currentKpi, dao.findById(id, KpiDataSource.class)));
			
		}
		//计算指标和父指标的可靠度,重置currentKpi
		km.updateSelfAndParentsKpiReliability(currentKpi.getId());
		currentKpi = dao.findById(currentKpi.getId(), KpiNormal.class);
		
		selectedNode.getChildren().clear();
		loadChildren(selectedNode);
		selectedNode.setExpanded(true);
		
		addSuccessMessage("引用新数据源成功！");
	}
	
	public void preImportKpi(){
		croot = new LibTreeNode("cRoot", null);
		List<KpiGroup> roots = km.findGroupRoots(); 
		for(KpiGroup r:roots){
			new LibTreeNode("croot",r,croot);
		}
		root.setExpanded(true);
	}
	public void importKpi(){
		if(selectedChildNode.getData().getClass().getSimpleName().equals("KpiNormal")){
			KpiNormal select = (KpiNormal) selectedChildNode.getData();
			if(select.equals(currentKpi)){
				addErrorMessage("不可引用自身！");
				return;
			}
			//看本指标的父是否包括child
			if(km.findImportKpiRepeatWithParent(currentKpi.getId(),select.getId())){
				addErrorMessage("不可引用父指标！");
				return;
			}
			//看本指标的子是否包括child
			if(km.findImportKpiRepeatWithChild(currentKpi.getId(),select.getId())){
				addErrorMessage("不可重复引用指标！");
				return;
			}
			//添加weight到数据库，添加到map，添加到当前
			String pid = currentKpi.getId();
			KpiWeight w = new KpiWeight("kpinormal","kpinormal",
					pid,select.getId());
			w = dao.createOrUpdate(w, KpiWeight.class);
			kpiWeights.add(new KpiWeightComplete(w,currentKpi,select));
			addSuccessMessage("成功增加引用指标！");
		}else{
			addErrorMessage("请选择引用指标！");
		}
	}
	public void preKpiInfoDia(KpiNormal child){
		currentChild = child;
	}
	public void removeImportKpi(KpiWeightComplete kw){
		km.removeKpiFromKpi(kw.getKpiweight().getPid(), kw.getKpiweight().getCid());
		loadKpiWeight();
		addSuccessMessage("成功移除引用！");
	}
	public void removeImportedDataSource(KpiWeightComplete kw){
		km.removeDataSourceFromKpi(kw.getKpiweight().getCid(),kw.getKpiweight().getPid());
		loadKpiWeight();
		addSuccessMessage("成功移除引用！");
	}
	public void onCNodeSelect(NodeSelectEvent event){
		selectedChildNode = event.getTreeNode();
	}
	
	public void onCNodeExpand(NodeExpandEvent event){
		selectedChildNode = event.getTreeNode();
		selectedChildNode.getChildren().clear();
		loadChildrenC(selectedChildNode);
		selectedChildNode.setExpanded(true);
	}
	@SuppressWarnings("rawtypes")
	private void loadChildrenC(TreeNode node){
		Class type = node.getData().getClass();
		if(type == KpiGroup.class){
			String parentId = ((KpiGroup)node.getData()).getId();
			List<KpiNormal> normals = km.findKpiByGroup(parentId);
			List<KpiGroup> groups = km.findGroupByPid(parentId);
			for(KpiGroup g : groups){
				new LibTreeNode("croot",g,node);
			}
			for(KpiNormal n : normals){
				new LibTreeNode("cnormal",n,node);
			}
		}
	}
	public void onCNodeCollapse(NodeCollapseEvent event){
		event.getTreeNode().setExpanded(false);
		event.getTreeNode().getChildren().clear();
	}
	
	public TreeNode getRoot() {
		return root;
	}

	public void setRoot(TreeNode root) {
		this.root = root;
	}

	public TreeNode getSelectedNode() {
		return selectedNode;
	}

	public void setSelectedNode(TreeNode selectedNode) {
		this.selectedNode = selectedNode;
	}

	public KpiNormal getCurrentKpi() {
		return currentKpi;
	}

	public void setCurrentKpi(KpiNormal currentKpi) {
		this.currentKpi = currentKpi;
	}

	public KpiGroup getCurrentGroup() {
		return currentGroup;
	}

	public void setCurrentGroup(KpiGroup currentGroup) {
		this.currentGroup = currentGroup;

	}
	public KpiDataSource getCurrentDataSource() {
		return currentDataSource;
	}
	public TreeNode getCroot() {
		return croot;
	}
	public void setCroot(TreeNode croot) {
		this.croot = croot;
	}
	public void setCurrentDataSource(KpiDataSource currentDataSource) {
		this.currentDataSource = currentDataSource;
	}
	@SuppressWarnings("rawtypes")
	public Class getCurrentType() {
		return currentType;
	}
	@SuppressWarnings("rawtypes")
	public void setCurrentType(Class currentType) {
		this.currentType = currentType;
	}
	public TreeNode getSelectedChildNode() {
		return selectedChildNode;
	}
	public void setSelectedChildNode(TreeNode selectedChildNode) {
		this.selectedChildNode = selectedChildNode;
	}
	public KpiNormal getCurrentChild() {
		return currentChild;
	}
	public void setCurrentChild(KpiNormal currentChild) {
		this.currentChild = currentChild;
	}
	public List<KpiDataSource> getSources() {
		return sources;
	}
	public void setSources(List<KpiDataSource> sources) {
		this.sources = sources;
	}
	public List<String> getSelectedSourceIds() {
		return selectedSourceIds;
	}
	public void setSelectedSourceIds(List<String> selectedSourceIds) {
		this.selectedSourceIds = selectedSourceIds;
	}
	public List<KpiLevel> getLevels() {
		return levels;
	}
	public void setLevels(List<KpiLevel> levels) {
		this.levels = levels;
	}
	public List<KpiWeightComplete> getDsWeights() {
		return dsWeights;
	}
	public void setDsWeights(List<KpiWeightComplete> dsWeights) {
		this.dsWeights = dsWeights;
	}
	public List<KpiWeightComplete> getKpiWeights() {
		return kpiWeights;
	}
	public void setKpiWeights(List<KpiWeightComplete> kpiWeights) {
		this.kpiWeights = kpiWeights;
	}
	
}

